package com.gitee.huanminabc.jcommon.reflect;

import com.gitee.huanminabc.jcommon.model.DataKeyValue;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

public class AnnotationUtil {

    //获取annotations中存在于set中的注解
    public static List<Annotation> getIncludeAnnotationList(Set<Class<? extends Annotation>> set, Annotation[] annotations) {
        List<Annotation> result = new ArrayList<>();
        for (Annotation annotation : annotations) {
            // 获取注解的运行时类型
            Class<? extends Annotation> annotationType = annotation.annotationType();
            // 检查该类型是否在允许的集合中
            if (set.contains(annotationType)) {
                result.add(annotation);
            }
        }
        return result;
    }

    public static Annotation getIncludeAnnotationFirst(Set<Class<? extends Annotation>> set, Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            // 获取注解的运行时类型
            Class<? extends Annotation> annotationType = annotation.annotationType();
            // 检查该类型是否在允许的集合中
            if (set.contains(annotationType)) {
                return annotation;
            }
        }
        return null;
    }

    //或者指定Field上的多个注解,返回找到的第一个
    public static DataKeyValue<Field, Annotation> getFieldAnnotationAny(Field field, Class<?>... annotationClass) {
        // 遍历注解类型数组
        for (Class<?> annotation : annotationClass) {
            // 获取方法上的注解
            Annotation annotation1 = field.getAnnotation((Class<Annotation>) annotation);
            if (annotation1 != null) {
                return new DataKeyValue<>(field, annotation1);
            }
        }
        return null;
    }

    //或者指定Field上的多个注解,返回全部的
    public static List<Annotation> getFieldAnnotations(Field field, Class<?>... annotationClass) {
        List<Annotation> annotations = new ArrayList<Annotation>();
        // 遍历注解类型数组
        for (Class<?> annotation : annotationClass) {
            // 获取方法上的注解
            Annotation annotation1 = field.getAnnotation((Class<Annotation>) annotation);
            if (annotation1 != null) {
                annotations.add(annotation1);
            }
        }
        return annotations;
    }

    //获取类中 指定注解方法
    public static Map<Method, Annotation> getAnnotationsMethods(Class clazz, Class annotationType) {
        Map<Method, Annotation> map = new HashMap<>();
        for (Method declaredMethod : clazz.getDeclaredMethods()) {
            Annotation annotation = declaredMethod.getAnnotation(annotationType);
            if (annotation != null) {
                map.put(declaredMethod, annotation);
            }
        }
        return map;
    }

    //获取类中属性指定注解
    public static <T extends Annotation> Map<Field, T> getAnnotationsFieldMap(Class clazz, Class<T> annotationType) {
        Map<Field, T> map = new HashMap<>();
        for (Field declaredField : clazz.getDeclaredFields()) {
            T annotation = declaredField.getAnnotation(annotationType);
            if (annotation != null) {
                map.put(declaredField, annotation);
            }
        }
        return map;
    }

    public static List<Field> getAnnotationsFields(Class clazz, Class annotationType) {
        List<Field> arrayList = new ArrayList<>();
        for (Field declaredField : clazz.getDeclaredFields()) {
            Annotation annotation = declaredField.getAnnotation(annotationType);
            if (annotation != null) {
                arrayList.add(declaredField);
            }
        }
        return arrayList;
    }


    public static <T extends Annotation> DataKeyValue<Field, T> getAnnotationsField(Class<?> clazz, Class<T> annotationType) {
        for (Field declaredField : clazz.getDeclaredFields()) {
            Annotation annotation = declaredField.getAnnotation(annotationType);
            if (annotation != null) {
                return new DataKeyValue<>(declaredField, (T) annotation);
            }
        }
        return null;
    }


    //获取指定方法上的多个注解,返回找到的第一个
    public static Annotation getMethodAnnotation(Method method, Class<?>... annotationClass) {
        // 遍历注解类型数组
        for (Class<?> annotation : annotationClass) {
            // 获取方法上的注解
            Annotation annotation1 = method.getAnnotation((Class<Annotation>) annotation);
            if (annotation1 != null) {
                return annotation1;
            }
        }
        return null;
    }

    //获取类上指定的注解
    public static <T extends Annotation> T getClassAnnotation(Class<?> clazz, Class<T> annotationClass) {
        // 获取类上的注解
        T annotation = clazz.getAnnotation(annotationClass);
        if (annotation != null) {
            return annotation;
        }
        // 如果类上没有，获取父类上的注解
        Class<?> superClass = clazz.getSuperclass();
        while (superClass != null) {
            annotation = superClass.getAnnotation(annotationClass);
            if (annotation != null) {
                return annotation;
            }
            superClass = superClass.getSuperclass();
        }
        return null;
    }

    //获取field上指定的注解
    public static <T extends Annotation> T getFieldAnnotation(Field field, Class<T> annotationClass) {
        // 获取字段上的注解
        T annotation = field.getAnnotation(annotationClass);
        if (annotation != null) {
            return annotation;
        }
        // 如果字段上没有，获取父类字段上的注解
        Class<?> superClass = field.getDeclaringClass().getSuperclass();
        while (superClass != null) {
            try {
                Field superField = superClass.getDeclaredField(field.getName());
                annotation = superField.getAnnotation(annotationClass);
                if (annotation != null) {
                    return annotation;
                }
            } catch (NoSuchFieldException e) {
                // Ignore
            }
            superClass = superClass.getSuperclass();
        }
        return null;
    }


    /**
     * 获取注解的属性值
     *
     * @param annotation   注解对象
     * @param propertyName 属性名称
     * @return 属性值
     */
    public static String getAnnotationPropertyValue(Annotation annotation, String propertyName) {
        try {
            // 获取注解的类
            Class<? extends Annotation> annotationClass = annotation.annotationType();

            // 获取注解中的 name 方法
            Method method = annotationClass.getDeclaredMethod(propertyName);
            // 调用注解的 name 方法获取值
            return (String) method.invoke(annotation);
        } catch (Exception e) {
            // 如果找不到属性或调用失败，返回 null
            return null;
        }
    }

    //有些时候需要获取注解的属性非String类型的值, 这个就需要用到了
    public static <T> T getAnnotationPropertyValueT(Annotation annotation, String propertyName, Class<T> tClass) {
        try {
            // 获取注解的类
            Class<? extends Annotation> annotationClass = annotation.annotationType();

            // 获取注解中的 name 方法
            Method method = annotationClass.getDeclaredMethod(propertyName);
            // 调用注解的 name 方法获取值
            return (T) method.invoke(annotation);
        } catch (Exception e) {
            // 如果找不到属性或调用失败，返回 null
            return null;
        }
    }


    //获取指定参数上的指定注解
    public static <T extends Annotation> T getParamAnnotation(Parameter parameter, Class<T> annotationName) {
        // 获取参数上的注解
        Annotation[] annotations = parameter.getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation.annotationType() == annotationName) {
                return (T) annotation;
            }
        }
        return null;
    }

}
